﻿using System;
using System.Collections.Generic;
using System.Security.Permissions;

using Moe.ECamel.Common.Contracts;
using Moe.ECamel.Common.Entities;
using Moe.ECamel.Common.Security;
using Moe.ECamel.Server.BL;

namespace Moe.ECamel.Server.Services
{
	/// <summary>
	/// Service Interface for Employees services.
	/// </summary>
	public class EmployeeService : ECamelService, IEmployeeService
	{
		public EmployeeService()
			: base()
		{	
		}

		public EmployeeService(ECamelService caller)
			: base(caller)
		{
		}

		#region IEmployeeService Members

		[PrincipalPermission(SecurityAction.Demand, Role = Operations.EmployeeView)]
		public List<Employee> GetEmployeesByLibrary(int libraryId)
		{
			// Execute operation via service BL:
			using (var bl = new EmployeeBL(GetReadOnlyDataContext()))
			{
				return bl.GetEmployeesByLibrary(libraryId);
			}
		}
		
		[PrincipalPermission(SecurityAction.Demand, Role = Operations.EmployeeAdd)]
		public ECamelError CreateEmployee(Employee employee)
		{
			return CreateEmployees(new Employee[] {employee});
		}
		
		[PrincipalPermission(SecurityAction.Demand, Role = Operations.EmployeeAdd)]
		public ECamelError CreateEmployees(IEnumerable<Employee> employees)
		{
			List<Customer> customers = new List<Customer>();
			using (var bl = new EmployeeBL(GetReadWriteDataContext()))
			{
				foreach (var employee in employees)
				{
					// Set employee role:
					employee.User.UserRoles.Add(new UserRoles { User = employee.User, RoleId = Roles.Employee });
					// Create customer for employee:
					Customer customer = new Customer();
					customer.User = employee.User;
					customer.LibraryId = employee.LibraryId;
					customers.Add(customer);

					// Create employee:
					ECamelError error = bl.CreateEmployee(employee);
					if (error != null)
						return error;
				}
			}

			// Create customers:
			using (var customerService = new CustomerService(this))
			{
				ECamelError error = customerService.CreateCustomers(customers);
				if (error != null)
					return error;
			}

			return SubmitChanges(null);
		}

		[PrincipalPermission(SecurityAction.Demand, Role = Operations.EmployeeEdit)]
		public ECamelError UpdateEmployee(Employee employee)
		{
			ECamelError error;

			// Update user:
			using (var userService = new UserService(this))
			{
				error = userService.UpdateUser(employee.User);
				if (error != null)
					return error;
			}
			// Update employee:
			using (var bl = new EmployeeBL(GetReadWriteDataContext()))
			{
				error = bl.UpdateEmployee(employee);
			}

			return SubmitChanges(error);
		}

		[PrincipalPermission(SecurityAction.Demand, Role = Operations.EmployeeChangeStatus)]
		public ECamelError UpdateEmployeeStatus(int employeeId, bool active)
		{
			var dataContext = GetReadWriteDataContext();
			using (var bl = new EmployeeBL(dataContext))
			{
				// Find employee:
				var employee = bl.GetEmployeeById(employeeId);
				// If status is same, do nothing:
				if (employee.IsActive == active)
					return null;
				// If employee is manager abort (employee cannot change its own status):
				if (employee.User.HasRole(Roles.Manager))
					return new ECamelError(MessageIds.EmployeeCannotChangeManagerStatus);

				// Update status:
				employee.IsActive = active;
				// Add/remote employee role from employee.
				if (active)
					employee.User.AddRole(Roles.Employee);
				else
					dataContext.UserRoles.DeleteOnSubmit(employee.User.GetUserRole(Roles.Employee));
			}

			SubmitChanges();
			return null;
		}
		
		[PrincipalPermission(SecurityAction.Demand, Role = Operations.EmployeeChangeManager)]
		public ECamelError ChangeManager(int libraryId, int employeeId)
		{
			var dataContext = GetReadWriteDataContext();
			using (var bl = new EmployeeBL(dataContext))
			{
				// Get old manager:
				var oldManager = bl.GetLibraryManager(libraryId);
				// Get new manager:
				var newManager = bl.GetEmployeeById(employeeId);
				// If new manager is actually old one, do nothing:
				if (oldManager != null && oldManager.EmployeeId == newManager.EmployeeId)
					return null;
				// Validate new manager is eligible to be a manager:
				if (!newManager.IsActive)
					return new ECamelError(MessageIds.EmployeeManagerCannotBeInactive);
				// Demote old manager, if any:
				if (oldManager != null)
					dataContext.UserRoles.DeleteOnSubmit(oldManager.User.GetUserRole(Roles.Manager));
				// Promote new manager:
				newManager.User.AddRole(Roles.Manager);
			}

			SubmitChanges();
			return null;
		}

		#endregion

		public IList<Employee> GetAllEmployees()
		{
			using (var bl = new EmployeeBL(GetReadWriteDataContext()))
			{
				return bl.GetAllEmployees();
			}
		}
	}
}